package com.shawn.springboot.integeration.netty.client;

import com.shawn.springboot.integeration.netty.exception.ApiException;
import com.shawn.springboot.integeration.netty.future.SyncWriteCache;
import com.shawn.springboot.integeration.netty.future.SyncWriteFuture;
import com.shawn.springboot.integeration.netty.model.ServerAddress;
import com.shawn.springboot.integeration.netty.msg.Request;
import com.shawn.springboot.integeration.netty.msg.Response;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author zhangjian
 * @title: NettyClient
 * @projectName 12-springboot学习
 * @description: 客户端具体实现
 * @date 2021/4/2711:39
 */
@Slf4j
public class NettyClient implements IClient {
    private final Channel channel;
    private final ServerAddress serverAddress;
    public NettyClient(Channel channel, ServerAddress serverAddress) {
        this.channel = channel;
        this.serverAddress = serverAddress;
    }

    @Override
    public boolean asyncReq(Request request) {
        channel.writeAndFlush(request);
        return true;
    }

    @Override
    public Response syncReq(Request request) throws ApiException {
        return syncReq(request,DEFAULT_TIMEOUT,DEFAULT_TIMEOUT_UNIT);
    }

    @Override
    public Response syncReq(Request request, long timeout, TimeUnit timeUnit) throws ApiException {
        log.info("request:[{}]",request);
        SyncWriteFuture syncWriteFuture = new SyncWriteFuture(request.getRequestId());
        SyncWriteCache.put(request.getRequestId(),syncWriteFuture);
        channel.writeAndFlush(request);
        Response response;
        try {
            response = syncWriteFuture.get(timeout,timeUnit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ApiException("请求失败");
        } catch (ExecutionException e) {
            throw new ApiException("请求失败");
        } catch (TimeoutException e) {
            throw new ApiException("请求超时");
        } finally {
            SyncWriteCache.clear(request.getRequestId());
        }
        return response;
    }

    @Override
    public ServerAddress getServerAddress() {
        return this.serverAddress;
    }

    @Override
    public void close() {
       if(null != channel && channel.isActive()) {
           channel.close();
       }
    }

    @Override
    public boolean isConnected() {
        return channel.isActive();
    }

    @Override
    public String getClientId() {
        return channel.id().asLongText();
    }
}
